{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "78491e09",
   "metadata": {},
   "source": [
    "### Table A5 (Appendices)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "3986ea69",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Loaded: jcr_mutiny_conflict_data.dta  |  Rows=1,599,624  Cols=60\n",
      "\\begin{table}\n",
      "\\caption{}\n",
      "\\label{}\n",
      "\\begin{center}\n",
      "\\begin{tabular}{lllll}\n",
      "\\hline\n",
      "                   & m1        & m2        & m3        & m4         \\\\\n",
      "\\hline\n",
      "Mutiny       & 0.371***  &           &           &            \\\\\n",
      "                   & (0.107)   &           &           &            \\\\\n",
      "Violent mutiny      &           & 0.747***  &           &            \\\\\n",
      "                   &           & (0.153)   &           &            \\\\\n",
      "Large mutiny         &           &           & 0.875***  &            \\\\\n",
      "                   &           &           & (0.167)   &            \\\\\n",
      "Mutiny duration     &           &           &           & 0.259***   \\\\\n",
      "                   &           &           &           & (0.064)    \\\\\n",
      "Military spending per soldier (logged) & -0.132*** & -0.132*** & -0.132*** & -0.132***  \\\\\n",
      "                   & (0.016)   & (0.016)   & (0.016)   & (0.016)    \\\\\n",
      "Years since last coup & 0.006***  & 0.006***  & 0.006***  & 0.006***   \\\\\n",
      "                   & (0.002)   & (0.002)   & (0.002)   & (0.002)    \\\\\n",
      "Civil conflict  & 0.594***  & 0.601***  & 0.605***  & 0.594***   \\\\\n",
      "                   & (0.053)   & (0.053)   & (0.053)   & (0.053)    \\\\\n",
      "Defense alliance    & -0.289*** & -0.287*** & -0.293*** & -0.288***  \\\\\n",
      "                   & (0.045)   & (0.045)   & (0.045)   & (0.045)    \\\\\n",
      "Capability ratio            & 0.501***  & 0.502***  & 0.503***  & 0.501***   \\\\\n",
      "                   & (0.055)   & (0.054)   & (0.055)   & (0.055)    \\\\\n",
      "Both democracy               & -0.360\n",
      "...\n",
      "\n",
      "LaTeX table written to: C:\\Users\\rmuhi\\OneDrive\\Desktop\\Mutiny_Conflict Paper_All\\Replication File\\table_A5.tex\n"
     ]
    }
   ],
   "source": [
    "# ----------------------------------------------------------\n",
    "# 0) Lightweight installer if packages are missing\n",
    "# ----------------------------------------------------------\n",
    "\n",
    "try:\n",
    "    import pandas as _pd; import statsmodels as _sm; import matplotlib as _mpl\n",
    "except Exception:\n",
    "    import sys, subprocess\n",
    "    subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", \"-U\", \"pandas\", \"statsmodels\", \"matplotlib\"])\n",
    "\n",
    "from pathlib import Path\n",
    "import pandas as pd\n",
    "import statsmodels.formula.api as smf\n",
    "from statsmodels.iolib.summary2 import summary_col\n",
    "\n",
    "\n",
    "# ----------------------------\n",
    "# 1) Load data\n",
    "# ----------------------------\n",
    "file_path = Path(r\"C:\\Users\\rmuhi\\OneDrive\\Desktop\\Mutiny_Conflict Paper_All\\Replication File\\jcr_mutiny_conflict_data.dta\")\n",
    "if not file_path.exists():\n",
    "    raise FileNotFoundError(f\"Could not find .dta file at: {file_path}\")\n",
    "\n",
    "data = pd.read_stata(file_path)\n",
    "print(f\"Loaded: {file_path.name}  |  Rows={len(data):,}  Cols={len(data.columns)}\")\n",
    "\n",
    "\n",
    "# ----------------------------\n",
    "# 3) Model formulas\n",
    "# ----------------------------\n",
    "formula1 = (\n",
    "    'dispute2 ~ mutiny_only + lmmilex_persol_t + years_since_coup + '\n",
    "    'ucdp_civconf_t2 + defense_target + capprop + jdem + majorpower + '\n",
    "    'cold_war + t_since + t2_since + t3_since'\n",
    ")\n",
    "\n",
    "formula2 = (\n",
    "    'dispute2 ~ violent_only + lmmilex_persol_t + years_since_coup + '\n",
    "    'ucdp_civconf_t2 + defense_target + capprop + jdem + majorpower + '\n",
    "    'cold_war + t_since + t2_since + t3_since'\n",
    ")\n",
    "\n",
    "formula3 = (\n",
    "    'dispute2 ~ size_only + lmmilex_persol_t + years_since_coup + '\n",
    "    'ucdp_civconf_t2 + defense_target + capprop + jdem + majorpower + '\n",
    "    'cold_war + t_since + t2_since + t3_since'\n",
    ")\n",
    "\n",
    "formula4 = (\n",
    "    'dispute2 ~ duration_only + lmmilex_persol_t + years_since_coup + '\n",
    "    'ucdp_civconf_t2 + defense_target + capprop + jdem + majorpower + '\n",
    "    'cold_war + t_since + t2_since + t3_since'\n",
    ")\n",
    "\n",
    "\n",
    "# ----------------------------\n",
    "# 4) Fit helper (HC1-robust, with fallback)\n",
    "# ----------------------------\n",
    "def fit_logit_robust(formula, df):\n",
    "    model = smf.logit(formula, df)\n",
    "    try:\n",
    "        res = model.fit(disp=False, cov_type='HC1')\n",
    "    except TypeError:\n",
    "        res0 = model.fit(disp=False)\n",
    "        res = res0.get_robustcov_results(cov_type='HC1')\n",
    "    return res\n",
    "\n",
    "result1 = fit_logit_robust(formula1, data)\n",
    "result2 = fit_logit_robust(formula2, data)\n",
    "result3 = fit_logit_robust(formula3, data)\n",
    "result4 = fit_logit_robust(formula4, data)\n",
    "\n",
    "\n",
    "# ----------------------------\n",
    "# 5) Build LaTeX table\n",
    "# ----------------------------\n",
    "regressor_order = [\n",
    "    'mutiny_only',\n",
    "    'violent_only',\n",
    "    'size_only',\n",
    "    'duration_only',\n",
    "    'lmmilex_persol_t',\n",
    "    'years_since_coup',\n",
    "    'ucdp_civconf_t2',\n",
    "    'defense_target',\n",
    "    'capprop',\n",
    "    'jdem',\n",
    "    'majorpower',\n",
    "    'cold_war',\n",
    "    'Intercept'  # will be renamed if shows as 'const'\n",
    "]\n",
    "\n",
    "info_dict = {\n",
    "    'N':         lambda x: f\"{int(x.nobs):d}\",\n",
    "    'Pseudo R²': lambda x: f\"{getattr(x, 'prsquared', float('nan')):.3f}\"\n",
    "}\n",
    "\n",
    "results = [result1, result2, result3, result4]\n",
    "\n",
    "tbl = summary_col(\n",
    "    results=results,\n",
    "    float_format='%0.3f',\n",
    "    stars=True,\n",
    "    model_names=['m1','m2','m3','m4'],\n",
    "    info_dict=info_dict,\n",
    "    regressor_order=regressor_order,\n",
    "    drop_omitted=True  # hide time polynomials from the body if not in order list\n",
    ")\n",
    "\n",
    "latex_lines = tbl.as_latex().splitlines()\n",
    "\n",
    "# Insert extra rows immediately after the Pseudo R² line\n",
    "insert_idx = next((i for i, ln in enumerate(latex_lines) if 'Pseudo R²' in ln), None)\n",
    "if insert_idx is not None:\n",
    "    checks = ' & ' + ' & '.join(['\\\\checkmark'] * len(results)) + r' \\\\'\n",
    "    for new_line in [r\"Time polynomials\" + checks, r\"Robust SE\" + checks]:\n",
    "        insert_idx += 1\n",
    "        latex_lines.insert(insert_idx, new_line)\n",
    "\n",
    "# Friendly labels (handle escaped & unescaped)\n",
    "replacements = {\n",
    "    'mutiny_only':              'Mutiny',\n",
    "    'mutiny\\\\_only':            'Mutiny',\n",
    "    'violent_only':              'Violent mutiny',\n",
    "    'violent\\\\_only':            'Violent mutiny',\n",
    "    'size_only':                'Large mutiny',\n",
    "    'size\\\\_only':              'Large mutiny',\n",
    "    'duration_only':           'Mutiny duration',\n",
    "    'duration\\\\_only':         'Mutiny duration',\n",
    "\n",
    "    'lmmilex_persol_t':         'Military spending per soldier (logged)',\n",
    "    'lmmilex\\\\_persol\\\\_t':     'Military spending per soldier (logged)',\n",
    "    'years_since_coup':         'Years since last coup',\n",
    "    'years\\\\_since\\\\_coup':     'Years since last coup',\n",
    "    'ucdp_civconf_t2':          'Civil conflict',\n",
    "    'ucdp\\\\_civconf\\\\_t2':      'Civil conflict',\n",
    "    'defense_target':           'Defense alliance',\n",
    "    'defense\\\\_target':         'Defense alliance',\n",
    "    'capprop':                  'Capability ratio',\n",
    "    'jdem':                     'Both democracy',\n",
    "    'majorpower':               'Major power',\n",
    "    'cold_war':                 'Cold War',\n",
    "    'cold\\\\_war':               'Cold War',\n",
    "    'Intercept':                'Constant',\n",
    "    'const':                    'Constant'\n",
    "}\n",
    "\n",
    "fixed_lines = []\n",
    "for line in latex_lines:\n",
    "    for old, new in replacements.items():\n",
    "        if old in line:\n",
    "            line = line.replace(old, new)\n",
    "    fixed_lines.append(line)\n",
    "\n",
    "custom_latex = \"\\n\".join(fixed_lines)\n",
    "\n",
    "# Preview and save\n",
    "print(custom_latex[:1500] + \"\\n...\\n\")\n",
    "out_tex = file_path.parent / \"table_A5.tex\"\n",
    "out_tex.write_text(custom_latex, encoding=\"utf-8\")\n",
    "print(f\"LaTeX table written to: {out_tex}\")\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
